package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.cache.CustomCache;
import com.atguigu.tingshu.common.constant.RabbitConstant;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.dto.album.AlbumSearchInfoDto;
import com.atguigu.tingshu.enums.album.AlbumOpenType;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService, InitializingBean {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    @Transactional
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo) {
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        // 付费的默认前5集免费试看
        if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())) {
            albumInfo.setTracksForFree(SystemConstant.TRACKS_FOR_FREE);
        }
        albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
        albumInfo.setUserId(AuthContextHolder.getUserId());
        this.save(albumInfo);
        Long albumId = albumInfo.getId();
        List<AlbumAttributeValueVo> albumAttrValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        List<AlbumAttributeValue> collect = albumAttrValueVoList.stream().map(item -> {
            AlbumAttributeValue albumAttrValue = new AlbumAttributeValue();
            albumAttrValue.setAlbumId(albumId);
            BeanUtils.copyProperties(item, albumAttrValue);
            return albumAttrValue;
        }).collect(Collectors.toList());
        Db.saveBatch(collect);
        this.initAlbumStat(albumId);
        if (albumInfo.getIsOpen().equals(AlbumOpenType.OPEN.getState())) {
            log.info("用户：{}，新增了编号为【{}】的专辑，并投递到消息队列【{}】中，等待上架",
                    AuthContextHolder.getUsername(),
                    albumInfo.getAlbumTitle(),
                    RabbitConstant.ALBUM_UP_QUEUE);
            rabbitTemplate.convertAndSend(RabbitConstant.ALBUM_EXCHANGE, RabbitConstant.ALBUM_UP_QUEUE, albumId);
        }
    }

    @Override
    public IPage<AlbumListVo> findUserAlbumPage(Integer pageNum, Integer pageSize, AlbumInfoQuery albumInfoQuery) {
        Page<AlbumListVo> page = new Page<>(pageNum, pageSize);
        albumInfoQuery.setUserId(AuthContextHolder.getUserId());
        return albumInfoMapper.findUserAlbumPage(page, albumInfoQuery);
    }

    @Override
    @Transactional
    public void removeAlbumInfo(Long id) {
        this.removeById(id);
        LambdaQueryWrapper<AlbumAttributeValue> attrValueWrapper = new LambdaQueryWrapper<>(AlbumAttributeValue.class);
        attrValueWrapper.eq(AlbumAttributeValue::getAlbumId, id);
        Db.remove(attrValueWrapper);
        LambdaQueryWrapper<AlbumStat> statWrapper = new LambdaQueryWrapper<>(AlbumStat.class);
        statWrapper.eq(AlbumStat::getAlbumId, id);
        Db.remove(statWrapper);
        log.info("用户：{}，删除了编号为【{}】的专辑，并投递到消息队列【{}】中，等待下架",
                AuthContextHolder.getUsername(),
                id,
                RabbitConstant.ALBUM_DOWN_QUEUE);
        rabbitTemplate.convertAndSend(RabbitConstant.ALBUM_EXCHANGE, RabbitConstant.ALBUM_DOWN_QUEUE, id);
    }

    @Override
    @CustomCache(prefix = RedisConstant.ALBUM_INFO_PREFIX, bloomFilter = RedisConstant.ALBUM_BLOOM_FILTER)
    public AlbumInfo getAlbumInfo(Long id) {
        AlbumInfo albumInfo = this.getById(id);
        List<AlbumAttributeValue> attrValueList = Db.lambdaQuery(AlbumAttributeValue.class)
                .eq(AlbumAttributeValue::getAlbumId, id).list();
        albumInfo.setAlbumAttributeValueVoList(attrValueList);
        return albumInfo;
    }

    @Override
    @Transactional
    public void updateAlbumInfo(Long id, AlbumInfoVo vo) {
        AlbumInfo albumInfo = this.getById(id);
        BeanUtils.copyProperties(vo, albumInfo);
        this.updateById(albumInfo);
        Db.remove(new LambdaQueryWrapper<>(AlbumAttributeValue.class).eq(AlbumAttributeValue::getAlbumId, id));
        List<AlbumAttributeValue> collect = vo.getAlbumAttributeValueVoList().stream().map(item -> {
            AlbumAttributeValue attrValue = new AlbumAttributeValue();
            BeanUtils.copyProperties(item, attrValue);
            attrValue.setAlbumId(id);
            return attrValue;
        }).collect(Collectors.toList());
        Db.saveOrUpdateBatch(collect);
        if (albumInfo.getIsOpen().equals(AlbumOpenType.OPEN.getState())) {
            log.info("用户：{}，新增了专辑【{}】，并投递到消息队列【{}】中，等待上架",
                    AuthContextHolder.getUsername(),
                    albumInfo.getAlbumTitle(),
                    RabbitConstant.ALBUM_UP_QUEUE);
            rabbitTemplate.convertAndSend(RabbitConstant.ALBUM_EXCHANGE, RabbitConstant.ALBUM_UP_RK, albumInfo.getId());
        }
    }

    @Override
    public List<AlbumInfo> findUserAllAlbumList() {
        Long userId = AuthContextHolder.getUserId();
        List<AlbumInfo> albumInfos = this.lambdaQuery()
                .eq(AlbumInfo::getUserId, userId)
                .select(AlbumInfo::getId, AlbumInfo::getAlbumTitle)
                .orderByDesc(AlbumInfo::getId)
                .list();
        return albumInfos;
    }

    @Override
    public AlbumInfoIndex getAlbumInfoById(Long id) {
        AlbumSearchInfoDto dto = albumInfoMapper.getAlbumInfoById(id);
        AlbumInfoIndex albumInfoIndex = BeanUtil.copyProperties(dto, AlbumInfoIndex.class);
        Result<UserInfoVo> result = userInfoFeignClient.getUserInfoVo(dto.getUserId());
        Assert.notNull(result, "用户信息查询失败！");
        if (result.getData() != null) albumInfoIndex.setAnnouncerName(result.getData().getNickname());
        List<AlbumAttributeValue> valueList = Db.lambdaQuery(AlbumAttributeValue.class)
                .eq(AlbumAttributeValue::getAlbumId, id).list();
        List<AttributeValueIndex> collect = valueList.stream()
                .map(item -> BeanUtil.copyProperties(item, AttributeValueIndex.class)).collect(Collectors.toList());
        albumInfoIndex.setAttributeValueIndexList(collect);
        return albumInfoIndex;
    }

    @Override
    public IPage<AlbumListVo> findAllAlbumPage(Integer page, Integer limit) {
        return this.albumInfoMapper.findUserAlbumPage(new Page<>(page, limit), new AlbumInfoQuery());
    }

    @Override
    public AlbumStatVo getAlbumStateByAlbumId(Long albumId) {
        return this.albumStatMapper.getAlbumStateByAlbumId(albumId);
    }

    @Override
    public List<Long> findLatelyUpdateAlbum(String startTime, String endTime) {
        return albumStatMapper.findLatelyUpdateAlbum(startTime, endTime);
    }

    @Override
    public List<AlbumStatVo> findAlbumStatVoList(List<Long> albumIds) {
        return this.albumStatMapper.findAlbumStatVoList(albumIds);
    }

    /**
     * 初始化统计数据
     *
     * @param albumId
     */
    private void initAlbumStat(Long albumId) {
        List<AlbumStat> list = new ArrayList<>();
        AlbumStat albumStat1 = new AlbumStat();
        albumStat1.setAlbumId(albumId);
        albumStat1.setStatType(SystemConstant.ALBUM_STAT_PLAY);
        albumStat1.setStatNum(0);
        list.add(albumStat1);
        AlbumStat albumStat2 = new AlbumStat();
        albumStat2.setAlbumId(albumId);
        albumStat2.setStatNum(0);
        albumStat2.setStatType(SystemConstant.ALBUM_STAT_SUBSCRIBE);
        list.add(albumStat2);
        AlbumStat albumStat3 = new AlbumStat();
        albumStat3.setAlbumId(albumId);
        albumStat3.setStatNum(0);
        albumStat3.setStatType(SystemConstant.ALBUM_STAT_BROWSE);
        list.add(albumStat3);
        AlbumStat albumStat4 = new AlbumStat();
        albumStat4.setAlbumId(albumId);
        albumStat4.setStatNum(0);
        albumStat4.setStatType(SystemConstant.ALBUM_STAT_COMMENT);
        list.add(albumStat4);
        Db.saveBatch(list);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        RBloomFilter<String> albumBloomFilter = this.redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        albumBloomFilter.tryInit(1000000, 0.03);
        List<AlbumInfo> list = this.list();
        if (CollUtil.isNotEmpty(list)) {
            list.forEach(item -> albumBloomFilter.add(RedisConstant.ALBUM_INFO_PREFIX + item.getId()));
        }
    }
}
